package com.code.soulnetty.modbus.biz;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lyf
 * @date 2022-12-16 21:42
 */
@Slf4j
@Component
public class ModbusCache {

    /**
     * {端口号:{寄存器开始地址,数据}}
     */
    private final Map<Integer, TreeMap<Integer, Pair<String, byte[]>>> DATA = new ConcurrentHashMap<>();
    private final Map<Integer, TreeMap<Integer, Boolean>> BIT_DATA = new ConcurrentHashMap<>();




    public void updateRegister(int port, int offset, String number, byte[] data) {
        final TreeMap<Integer, Pair<String, byte[]>> integerTreeMap = DATA.computeIfAbsent(port,
                d -> new TreeMap<>(Comparator.comparingInt(o -> (int) o)));
        synchronized (integerTreeMap) {
            integerTreeMap.put(offset, Pair.of(number, data));
        }
    }

    public void update(int port, Map<Integer, Pair<String, byte[]>> data) {
        final TreeMap<Integer, Pair<String, byte[]>> integerTreeMap = DATA.computeIfAbsent(port,
                d -> new TreeMap<>(Comparator.comparingInt(o -> (int) o)));
        synchronized (integerTreeMap) {
            integerTreeMap.putAll(data);
        }
    }

    public void updateBit(int port, Map<Integer, Boolean> data) {
        final TreeMap<Integer, Boolean> integerTreeMap = BIT_DATA.computeIfAbsent(port,
                d -> new TreeMap<>(Comparator.comparingInt(o -> (int) o)));
        synchronized (integerTreeMap) {
            integerTreeMap.putAll(data);
        }
    }

    public byte[] get(int port, int startOffset, int size) {
        final TreeMap<Integer, Pair<String, byte[]>> integerTreeMap = DATA.get(port);
        if (integerTreeMap == null) {
            return null;
        }
        byte[] result = new byte[size];
        final SortedMap<Integer, Pair<String, byte[]>> startMap = integerTreeMap.tailMap(startOffset);
        final Set<Integer> integers = startMap.keySet();
        for (int index : integers) {
            final byte[] bytes = startMap.get(index).getRight();
            //寄存器数量
            int diff = (index - startOffset) << 1;
            if (diff + bytes.length > size) {
                break;
            }
            log.info("[NEXT] {},{}", index, startMap.get(index));
            System.arraycopy(bytes, 0, result, diff, bytes.length);
        }
        return result;
    }

    public byte[] getBit(int port, int startOffset, int size) {
        final TreeMap<Integer, Boolean> bitMap = BIT_DATA.get(port);
        if (bitMap == null) {
            return null;
        }
        int byteSize = ((size - 1) / 8) + 1;
        byte[] result = new byte[byteSize];
        final SortedMap<Integer, Boolean> tailMap = bitMap.tailMap(startOffset);
        final Set<Integer> integers = tailMap.keySet();
        for (int index : integers) {
            int diff = (index - startOffset);
            if (diff + 1 > size) {
                break;
            }
            byte res = (byte) (tailMap.get(index) ? 1 : 0);
            result[diff / 8] |= (byte) (res << (diff % 8));
//            log.info("[NEXT_BIT] {},{},{},{}", index, tailMap.get(index),
//                    Integer.toBinaryString(result[diff / 8]), diff / 8);
        }
        return result;
    }

    public Boolean getBit(int port, int startOffset) {
        final TreeMap<Integer, Boolean> bitMap = BIT_DATA.get(port);
        if (bitMap == null) {
            return null;
        }
        return bitMap.get(startOffset);
    }

    public Pair<String, byte[]> get(int port, int startOffset) {
        final TreeMap<Integer, Pair<String, byte[]>> integerTreeMap = DATA.get(port);
        if (integerTreeMap == null) {
            return null;
        }
        return integerTreeMap.get(startOffset);
    }


}

